/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 */

import type { Worker } from 'cluster';
import cluster from 'cluster';
import process from 'process';

import { levels } from 'log4js';

import { boot } from '../../boot/index.js';
import { BuildEvent } from '../../common/daemon-protocol/build-event.js';
import { coreParameter } from '../../internal/data/global-core-parameters.js';
import { initStartData, refreshDaemonProcessEnv } from '../../internal/data/global-data.js';
import { watchWorker } from '../../internal/pool/worker-pool/watch-worker.js';
import { evaluateLogLevel } from '../../log/hvigor-log.js';
import { HvigorCliOptions } from '../../util/options/hvigor-cli-options.js';
import { configureDaemon, HvigorDaemonLogger } from '../log/hvigor-daemon-log.js';
import { setRunning } from './watch-config-file.js';
import { WORKER_PROCESS_EVENT_ID } from './worker-process-event-id.js';

/**
 * 在worker进程退出前完成相应处理动作，如维护注册表信息
 * @param _log logger
 */

function addExitHandler(_log: HvigorDaemonLogger) {
  let isExiting = false;

  const handleExit = (exitCode: number, error?: any) => {
    if (isExiting) {
      return;
    }
    isExiting = true;

    let hasDoExit = false;
    const doExit = () => {
      _log.debug(`hvigor worker: worker process exit. exitCode=${exitCode}`);
      if (hasDoExit) {
        return;
      }
      hasDoExit = true;
      setImmediate(() => process.exit(exitCode));
    };
    if (error) {
      _log.debug(`hvigor worker: Exit with error: ${error}`);
      if (error.stack) {
        _log.debug(`hvigor worker: Stack: ${error.stack}`);
      }
      process.send!({
        type: WORKER_PROCESS_EVENT_ID.FAILED,
        content: error.stack ?? error.message ?? error,
      });
    }

    setTimeout(() => {
      _log.debug('hvigor worker: Set process exit timeout in 1000 ms.');
      doExit();
    }, 1000);
  };

  const registryProcessListener = () => {
    process.on('exit', (code) => {
      _log.debug(`hvigor worker: worker process exit (${code}).`);
      handleExit(code);
    });

    // 用 128 + 信号编号 得到最终的退出码
    process.on('SIGHUP', () => handleExit(128 + 1));
    process.on('SIGINT', () => handleExit(128 + 2));
    process.on('SIGTERM', () => handleExit(128 + 15));

    // 在 Windows 中按下 <Ctrl>+<Break> 会被触发
    process.on('SIGBREAK', () => handleExit(128 + 21));

    // 退出码 1 代表未捕获的错误导致进程退出
    process.on('uncaughtException', (error) => handleExit(1, error));
    process.on('unhandledRejection', (error) => handleExit(1, error));
  };

  registryProcessListener();
}

function initWorkerLogger() {
  const logLevelByProcessArgv = process.env._logLevel ?? levels.INFO;

  configureDaemon();
  const _log = HvigorDaemonLogger.getLogger('daemon');
  const level = levels.getLevel(logLevelByProcessArgv);
  evaluateLogLevel(level, ['daemon']);
  return _log;
}

function onOnline(worker: Worker, _log: HvigorDaemonLogger) {
  worker.on('online', () => {
    _log.debug(`hvigor worker: worker ${process.pid} with worker id ${worker.id} is online.`);
  });
}

function onDisconnect(worker: Worker, _log: HvigorDaemonLogger) {
  worker.on('disconnect', () => {
    _log.debug(`hvigor worker: worker ${process.pid} with worker id ${worker.id} is disconnected.`);
  });
}

function onExit(worker: Worker, _log: HvigorDaemonLogger) {
  worker.on('exit', (code, signal) => {
    _log.debug(`hvigor worker: worker ${process.pid} with worker id ${worker.id} exit. (${code || signal})`);
  });
}

function onError(worker: Worker, _log: HvigorDaemonLogger) {
  process.on('error', (error) => {
    _log.error(`hvigor worker: worker ${process.pid} with worker id ${worker.id} has an error. Error: ${error}`);
    if (error.stack) {
      _log.error(error.stack);
    }
  });
}

function onBuild(worker: Worker, _log: HvigorDaemonLogger) {
  worker.on('message', async (message) => {
    if (message.type === BuildEvent.COMMON_BUILD) {
      setRunning(true);
      const cliArgv = message.content as HvigorCliOptions;
      try {
        if (cliArgv.hotCompile && cliArgv._.includes('assembleDevHqf')) {
          watchWorker.sendCompileMsgToWorker();
          return;
        }
        refreshDaemonProcessEnv(cliArgv);
        initStartData(cliArgv);
      } catch (e: any) {
        _log.error(e);
        process.send!({
          type: WORKER_PROCESS_EVENT_ID.FAILED,
          content: e.stack ?? e.message ?? e,
        });
        return;
      }
      evaluateLogLevel(coreParameter.startParams.logLevel, ['daemon']);

      try {
        await boot(message.content);
      } catch (e: any) {
        _log.error(e);
        process.send!({
          type: WORKER_PROCESS_EVENT_ID.FAILED,
          content: e.stack ?? e.message ?? e,
        });
      }
    }
  });
}

function initWorkerProcessListeners(_log: HvigorDaemonLogger) {
  const worker = cluster.worker!;
  onOnline(worker, _log);
  onDisconnect(worker, _log);
  onExit(worker, _log);
  onError(worker, _log);
  onBuild(worker, _log);
}

export function registryWorkerProcessListener() {
  if (cluster.isWorker) {
    const _log = initWorkerLogger();
    initWorkerProcessListeners(_log);
    addExitHandler(_log);
  }
}
